package com.samge.fandroid

import kotlinx.coroutines.*
import org.junit.Test

import java.util.*

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
class LaunchTest {

    /**
     * 注意一旦lazy协程体没有通过start执行完毕或者通过cancel取消掉，则runBlocking永远不会退出。
     * runBlocking会等到里面全部协程结束才退出
     *
     * 打印出:
     * 1
     * 3
     * 4
     */
    @Test
    fun lazy1() = runBlocking {
        println("1")
        val job = launch(start = CoroutineStart.LAZY) {
            println("2")
        }
        println("3")
        job.start()
//        job.cancel()
        delay(3000)
        println("4")
    }

    @Test
    fun lazy2() = runBlocking {
        println("1")
        val job = launch(start = CoroutineStart.LAZY) {
            println("2")
        }
        println("3")
        //job.start()
        //job.cancel()
        delay(3000)
        println("4")
    }

    @Test
    fun launch_default() = runBlocking {
        println("1")
        val job = launch(start = CoroutineStart.DEFAULT) {
            println("2")
        }
        println("3")
        //job.start()
        //job.cancel()
        delay(3000)
        println("4")
    }

    @Test
    fun launch_undispatched() = runBlocking {
        println("1")
        val job = launch(start = CoroutineStart.UNDISPATCHED) {
            println("2")
        }
        println("3")
        //job.start()
        //job.cancel()
//        delay(3000)
        println("4")
    }

    @Test
    fun testLaunch() {
        GlobalScope.launch { // 在后台启动一个新的协程，协程的生命周期和应用程序生命周期绑定
            delay(1000L) // 非阻塞的等待 1 秒钟（默认时间单位是毫秒）
            println("World!")
        }
        println("Hello,") // 协程已在等待时主线程还在继续
        Thread.sleep(2000L) // 阻塞主线程 2 秒钟
        /*
    通过GlobalScope创建的新协程的生命周期受应用程序的生命周期限制，类似java中的守护线程，
    所以当主线程运行结束之后，GlobalScope.launch方法创建的协程也就消失了
    所以你会发现如果你将Thread.sleep(2000L)这行代码取消掉，你会发现只打印了Hello
    这是因为主线程打印了Hello之后，主程序退出了，然后GlobalScope.launch启动的协程需要延迟1秒才打印，但是随着主线程的退出，协程也退出了，顾不打印World
    */
    }

    //使用GlobalScope单例对象调用launch
    @Test
    fun testLaunch2() {
        val job = GlobalScope.launch {
            //调用其他挂起函数
            for (i in 1..5) {
                delay(1000)   //每隔1s打印一个数字
                println("--->$i")
            }
        }

        Timer().schedule(object : TimerTask() {
            override fun run() {
                println("-----------------------------3s时间到----------------------------")
                println("协程是否活动？${job.isActive}")          //true
                println("协程是否执行完毕？${job.isCompleted}")   //false
                println("协程是否取消？${job.isCancelled}")       //false

                job.cancel(CancellationException("中途取消协程，生命周期结束"))

                println("\n协程是否活动？${job.isActive}")          //false
                println("协程是否执行完毕？${job.isCompleted}")   //false
                println("协程是否取消？${job.isCancelled}")      //true
            }
        }, 3000)   //3s后结束协程
        Thread.sleep(5000)  //阻止jvm退出
    }

    @Test
    fun testLaunch3() = runBlocking {
        /***
         *
        缺省	默认为DEFAULT
        DEFAULT	立即等待被调度执行()
        ATOMIC	立即等待被调度执行，并且开始执行前无法被取消，直到执行完毕或者遇到第一个挂起点suspend
        UNDISPATCHED	立即在当前线程执行协程体内容，自动执行，不需要等待被调用
        LAZY	需要手动触发才会进入等待调度，定义后必须手动调用才会执行

        https://blog.csdn.net/weixin_45365889/article/details/100336198
         */
        val job = GlobalScope.launch {
            //通过async{}构建的协程默认会立即执行，因为默认启动模式为CoroutineStart.DEFAULT
            val deferred1 = async(start = CoroutineStart.ATOMIC){
//                delay(2000)
                println("1 子协程返回数据")
                "deferred1"
            }
            val deferred2 = async(start = CoroutineStart.DEFAULT){
                delay(1000)
                println("2 子协程返回数据")
                "deferred2"
            }
            println("等待两个结果返回")
            //async{}的执行结果被封装在Deferred对象中，需要调用await()获取结果值
//            val result1 = deferred1.await()  //获取第1个子协程的返回值
            val result1 = ""
            val result2 = deferred2.await()  //获取第2个子协程的返回值
            println("返回数据:$result1 - $result2")   //合并两个返回结果 deferred1 - deferred2
        }
        Thread.sleep(5000)  //阻止jvm退出
    }

    @Test
    fun test(){
        testLaunch3()
        launch_undispatched()
    }
}